package com.opencee.cloud.msg.service.impl.push;

import cn.jiguang.common.TimeUnit;
import cn.jiguang.common.resp.APIConnectionException;
import cn.jiguang.common.resp.APIRequestException;
import cn.jpush.api.JPushClient;
import cn.jpush.api.push.PushResult;
import cn.jpush.api.push.model.Options;
import cn.jpush.api.push.model.Platform;
import cn.jpush.api.push.model.PushPayload;
import cn.jpush.api.push.model.audience.Audience;
import cn.jpush.api.push.model.notification.AndroidNotification;
import cn.jpush.api.push.model.notification.IosNotification;
import cn.jpush.api.push.model.notification.Notification;
import cn.jpush.api.push.model.notification.WinphoneNotification;
import cn.jpush.api.report.ReceivedsResult;
import cn.jpush.api.report.UsersResult;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Maps;
import com.opencee.cloud.msg.service.MsgPushSenderService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.Map;

/**
 * 极光推送服务
 *
 * @author yadu
 */
@Slf4j
@Service("jpush")
public class JPushSenderServiceImpl implements MsgPushSenderService {

    /**
     * 推送消息
     *
     * @param client
     * @param alias
     * @param tags
     * @param title
     * @param alert
     * @param extras
     * @return
     * @throws Exception
     */
    public String sendPush(JPushClient client, Boolean isApnsProduction, String[] alias, String[] tags, String title, String content, Map<String, String> extras) throws Exception {
        PushPayload payload = null;
        Platform pushPlatform = Platform.all();
        if (extras == null) {
            extras = Maps.newHashMap();
        }
        if (alias != null && alias.length > 0 && (tags == null || tags.length == 0)) {
            // 根据别名推送
            payload = buildPushObject_all_all_alias(pushPlatform, isApnsProduction, alias, title, content, extras);
        } else if ((alias == null || alias.length == 0) && tags != null && tags.length > 0) {
            // 根据tag[]推送
            payload = buildPushObject_all_all_tag(pushPlatform, isApnsProduction, tags, title, content, extras);
        } else if (alias != null && alias.length > 0 && tags != null && tags.length > 0) {
            // 别名和tags[] 推送通知
            payload = buildPushObject_all_all_aliasAndTag(pushPlatform, isApnsProduction, alias, tags, title, content, extras);
        } else {
            // 推送所有
            payload = buildPushObject_all_all(pushPlatform, isApnsProduction, title, content, extras);
        }
        if (log.isDebugEnabled()) {
            log.debug("jpush请求:{}", payload.toString());
        }
        PushResult result = client.sendPush(payload);
        if (log.isDebugEnabled()) {
            log.debug("jpush推送结果{}", result);
        }
        return result.toString();
    }


    /**
     * 查询记录推送成功条数
     *
     * @param mid
     */
    public void countPush(JPushClient client, String mid) {
        try {
            ReceivedsResult result = client.getReportReceiveds(mid);
            ReceivedsResult.Received received = result.received_list.get(0);
            log.debug("android_received:" + received.android_received
                    + "\nios:" + received.ios_apns_sent);
            log.debug("Got result - " + result);
        } catch (APIConnectionException e) {
            log.error("Connection error, should retry later", e);
        } catch (APIRequestException e) {
            log.error("Should review the error, and fix the request", e);
            log.info("HTTP Status: " + e.getStatus());
            log.info("Error Code: " + e.getErrorCode());
            log.info("Error Message: " + e.getErrorMessage());
        }
    }

    /**
     * 统计用户数据。需要vip用户才能访问
     */
    public void getReportUser(JPushClient client, TimeUnit timeUnit, String start, Integer duration) {
        try {
            UsersResult result = client.getReportUsers(timeUnit, start, duration);
            log.debug("Got result - " + result);
        } catch (APIConnectionException e) {
            // Connection error, should retry later
            log.error("Connection error, should retry later", e);
        } catch (APIRequestException e) {
            // Should review the error, and fix the request
            log.error("Should review the error, and fix the request", e);
            log.info("HTTP Status: " + e.getStatus());
            log.info("Error Code: " + e.getErrorCode());
            log.info("Error Message: " + e.getErrorMessage());
        }
    }

    /**
     * 根据别名通知推送
     *
     * @return
     * @ 别名
     * @ alert 推送内容
     */
    public PushPayload buildPushObject_all_all_alias(Platform platform, Boolean apns, String[] alias, String title, String alert, Map<String, String> map) {
        return PushPayload
                .newBuilder()
                .setPlatform(platform)
                .setAudience(Audience.alias(alias))
                .setOptions(Options.newBuilder().setApnsProduction(apns).build())
                .setNotification(
                        Notification
                                .newBuilder()
                                .addPlatformNotification(
                                        IosNotification.newBuilder()
                                                .setAlert(alert)
                                                .addExtras(map).build())
                                .addPlatformNotification(
                                        AndroidNotification.newBuilder()
                                                .setAlert(alert)
                                                .setTitle(title).addExtras(map)
                                                .build())
                                .addPlatformNotification(
                                        WinphoneNotification.newBuilder()
                                                .setAlert(alert)
                                                .addExtras(map).build())
                                .build()).build();
    }

    /**
     * 根据tag通知推送
     *
     * @return
     * @ 别名
     * @ alert 推送内容
     */
    public PushPayload buildPushObject_all_all_tag(Platform platform, Boolean apns, String[] tags, String title, String alert, Map<String, String> map) {
        return PushPayload
                .newBuilder()
                .setPlatform(platform)
                .setAudience(Audience.tag(tags))
                .setOptions(Options.newBuilder().setApnsProduction(apns).build())
                .setNotification(
                        Notification
                                .newBuilder()
                                .addPlatformNotification(
                                        IosNotification.newBuilder()
                                                .setAlert(alert)
                                                .addExtras(map).build())
                                .addPlatformNotification(
                                        AndroidNotification.newBuilder()
                                                .setAlert(alert)
                                                .setTitle(title).addExtras(map)
                                                .build())
                                .addPlatformNotification(
                                        WinphoneNotification.newBuilder()
                                                .setAlert(alert)
                                                .addExtras(map).build())
                                .build()).build();
    }

    /**
     * 根据tag通知推送
     *
     * @return
     * @ alias 别名
     * @ alert 推送内容
     */
    public PushPayload buildPushObject_all_all_aliasAndTag(Platform platform, Boolean apns, String[] alias, String[] tags, String alert, String title, Map<String, String> map) {
        return PushPayload
                .newBuilder()
                .setPlatform(platform)
                .setAudience(Audience.alias(alias))
                .setAudience(Audience.tag(tags))
                .setOptions(Options.newBuilder().setApnsProduction(apns).build())
                .setNotification(
                        Notification
                                .newBuilder()
                                .addPlatformNotification(
                                        IosNotification.newBuilder()
                                                .setAlert(alert)
                                                .addExtras(map).build())
                                .addPlatformNotification(
                                        AndroidNotification.newBuilder()
                                                .setAlert(alert)
                                                .setTitle(title).addExtras(map)
                                                .build())
                                .addPlatformNotification(
                                        WinphoneNotification.newBuilder()
                                                .setAlert(alert)
                                                .addExtras(map).build())
                                .build()).build();
    }

    /**
     * 根据通知推送
     *
     * @return
     * @ alias 别名
     * @ alert 推送内容
     */
    public PushPayload buildPushObject_all_all(Platform platform, Boolean apns, String title, String alert, Map<String, String> map) {
        return PushPayload
                .newBuilder()
                .setPlatform(platform)
                .setAudience(Audience.all())
                .setOptions(Options.newBuilder().setApnsProduction(apns).build())
                .setNotification(
                        Notification
                                .newBuilder()
                                .addPlatformNotification(
                                        IosNotification.newBuilder()
                                                .setAlert(alert)
                                                .addExtras(map).build())
                                .addPlatformNotification(
                                        AndroidNotification.newBuilder()
                                                .setAlert(alert)
                                                .setTitle(title).addExtras(map)
                                                .build())
                                .addPlatformNotification(
                                        WinphoneNotification.newBuilder()
                                                .setAlert(alert)
                                                .addExtras(map).build())
                                .build()).build();
    }


    /**
     * 根据别名推送
     *
     * @param props   配置信息
     * @param alias
     * @param title
     * @param content
     * @param url
     * @param extras
     */
    @Override
    public String pushByAlias(JSONObject props, String[] alias, String title, String content, String url, Map<String, String> extras) throws Exception {
        JPushSdk sdk = props.toJavaObject(JPushSdk.class);
        JPushClient client = new JPushClient(sdk.getAppSecret(), sdk.getAppKey());
        return this.sendPush(client, sdk.isApnsProduction(), alias, null, title, content, extras);
    }

    /**
     * 根据标签推送
     *
     * @param props   配置信息
     * @param tags
     * @param title
     * @param content
     * @param url
     * @param extras
     */
    @Override
    public String pushByTags(JSONObject props, String[] tags, String title, String content, String url, Map<String, String> extras) throws Exception {
        JPushSdk sdk = props.toJavaObject(JPushSdk.class);
        JPushClient client = new JPushClient(sdk.getAppSecret(), sdk.getAppKey());
        return this.sendPush(client, sdk.isApnsProduction(), null, tags, title, content, extras);
    }

    /**
     * 推送所有
     *
     * @param props
     * @param title
     * @param content
     * @param url
     * @param extras
     */
    @Override
    public String pushAll(JSONObject props, String title, String content, String url, Map<String, String> extras) throws Exception {
        JPushSdk sdk = props.toJavaObject(JPushSdk.class);
        JPushClient client = new JPushClient(sdk.getAppSecret(), sdk.getAppKey());
        return this.sendPush(client, sdk.isApnsProduction(), null, null, title, content, extras);
    }
}
